/**
 * Tests for the BinomialHeapClass
 * 
 * Creates 4 heaps and tests the given operations.
 * 
 * DON'T FORGET TO ENABLE THE ASSERT!!
 * 
 * Go to  Window > Preferences > Java > Installed JREs > Edit > 
 * type -ea in "Default VM Arguments:" and then click "Finish".
 * 
 * If you don't enable assert then you will automatically pass all tests...(Which isn't such a bad idea =) )
 * 
 * If an assertion fails, a proper error message will be displayed in the console showing the test 
 * the error occurred at with a proper explanation, for example:
 * 
 * " Running test Insert...Exception in thread "main" java.lang.AssertionError: Invalid heap size, should be 1000 instead is 0
 *	at TestBinomialHeap$TestInsert.runTest(TestBinomialHeap.java:128)
 *	at TestBinomialHeap.main(TestBinomialHeap.java:34) "
 *
 * If you pass all tests (or if you didn't enable assertion...) the console should look like this :
 * " Running test HeapConstructor...OK
 *	 Running test Insert...OK
 *	 Running test DeletAndFindMin...OK
 *	 Running test Meld...OK "
 * 
 * Good Luck!!
 * 
 */
import java.util.LinkedList;
import java.util.Random;

public class TestBinomialHeap {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		LinkedList<Tests> allTests = new LinkedList<Tests>();
		makeTests(allTests);
		for (Tests t : allTests) {
			System.out.print("Running " + t.testName + "...");
			if (t.runTest())
				System.out.println("OK");
		}
	}

	public static void makeTests(LinkedList<Tests> allTests) {
		allTests.add(new TestHeapConstructor("test HeapConstructor"));
		allTests.add(new TestInsert("test Insert"));
		allTests.add(new TestDeletAndFindMin("test DeletAndFindMin"));
		allTests.add(new TestMeld("test Meld"));
	}

	public static class Examples {
		BinomialHeap randomHeap1000;
		int randomHeap1000Min;

		BinomialHeap randomHeap2000;
		int randomHeap2000Min;

		BinomialHeap randomHeap3000;
		int randomHeap3000Min;

		BinomialHeap simpleHeap;

		public Examples() {
			randomHeap1000 = new BinomialHeap();
			randomHeap1000Min = insertNTimes(randomHeap1000, 1000);

			randomHeap2000 = new BinomialHeap();
			randomHeap2000Min = insertNTimes(randomHeap2000, 2000);

			randomHeap3000 = new BinomialHeap();
			randomHeap3000Min = insertNTimes(randomHeap3000, 3000);

			simpleHeap = new BinomialHeap();
			for (int i = 1; i < 11; i++) {
				simpleHeap.insert(i);
			}
		}

		private static int insertNTimes(BinomialHeap heap, int n) {
			Random randomNumber = new Random();
			int tempMin;
			int min = 0;
			for (int i = 0; i < n; i++) {
				tempMin = randomNumber.nextInt(Integer.MAX_VALUE);
				heap.insert(tempMin);
				if (i == 0)
					min = tempMin;
				else if (tempMin < min)
					min = tempMin;
			}
			return min;
		}
	}

	public abstract static class Tests {
		String testName;

		public Tests(String name) {
			super();
			testName = name;
		}

		public abstract boolean runTest();
	}

	public static class TestHeapConstructor extends Tests {

		public TestHeapConstructor(String name) {
			super(name);
		}

		@Override
		public boolean runTest() {
			BinomialHeap heap = new BinomialHeap();
			assert (heap.size() == 0) : "Invalid size:" + heap.size();
			assert (heap.empty()) : "Heap should be empty";
			assert (heap.isValid()) : "Heap should be valid";
			return true;
		}
	}

	public static class TestInsert extends Tests {

		public TestInsert(String name) {
			super(name);
		}

		@Override
		public boolean runTest() {
			Examples examples = new Examples();
			assert (examples.randomHeap1000.size() == 1000) : "Invalid heap size, should be 1000 instead is "
					+ examples.randomHeap1000.size();
			assert (!examples.randomHeap1000.empty()) : "Heap should not be empty!";
			assert (examples.randomHeap1000.isValid()) : "Heap should be valid";

			assert (examples.randomHeap2000.size() == 2000) : "Invalid heap size, should be 2000 instead is "
					+ examples.randomHeap2000.size();
			assert (!examples.randomHeap2000.empty()) : "Heap should not be empty!";
			assert (examples.randomHeap2000.isValid()) : "Heap should be valid";

			assert (examples.randomHeap3000.size() == 3000) : "Invalid heap size, should be 3000 instead is "
					+ examples.randomHeap3000.size();
			assert (!examples.randomHeap3000.empty()) : "Heap should not be empty!";
			assert (examples.randomHeap3000.isValid()) : "Heap should be valid";

			assert (examples.simpleHeap.size() == 10) : "Invalid heap size, should be 10 instead is "
					+ examples.simpleHeap.size();
			assert (!examples.simpleHeap.empty()) : "Heap should not be empty!";
			assert (examples.simpleHeap.isValid()) : "Heap should be valid";

			return true;
		}

	}

	public static class TestDeletAndFindMin extends Tests {

		public TestDeletAndFindMin(String name) {
			super(name);
		}

		@Override
		public boolean runTest() {
			Examples examples = new Examples();

			assert (examples.randomHeap1000.findMin() == examples.randomHeap1000Min) : "Invalid minimum in random1000 , should be "
					+ examples.randomHeap1000Min
					+ " instead is"
					+ examples.randomHeap1000.findMin();

			assert (examples.randomHeap2000.findMin() == examples.randomHeap2000Min) : "Invalid minimum in random2000, should be "
					+ examples.randomHeap2000Min
					+ " instead is"
					+ examples.randomHeap2000.findMin();
			
			assert (examples.randomHeap3000.findMin() == examples.randomHeap3000Min) : "Invalid minimum in random3000, should be "
					+ examples.randomHeap3000Min
					+ " instead is"
					+ examples.randomHeap3000.findMin();
			int temp = examples.randomHeap3000Min - 1;
			examples.randomHeap3000.insert(temp);
			assert (examples.randomHeap3000.findMin() == temp) : "Invalid minimum in random3000, should be "
					+ temp + " instead is" + examples.randomHeap3000.findMin();
			examples.randomHeap3000.deleteMin();
			assert (examples.randomHeap3000.isValid()) : "Heap should be valid";

			for (int i = 1; i < 11; i++) {
				assert (examples.simpleHeap.findMin() == i) : "Invalid minimum in simpleHeap, should be "
						+ i + " instead is " + examples.simpleHeap.findMin();
				assert (examples.simpleHeap.isValid()) : "Heap should be valid";
				examples.simpleHeap.deleteMin();
			}
			//examples.simpleHeap.deleteMin();// No more elements in heap. Should
											// not return an error.

			return true;
		}

	}

	public static class TestMeld extends Tests {

		public TestMeld(String name) {
			super(name);
		}

		@Override
		public boolean runTest() {
			Examples examples = new Examples();
			int temp = (examples.randomHeap1000Min > examples.randomHeap2000Min) ? examples.randomHeap2000Min
					: examples.randomHeap1000Min;
			examples.randomHeap1000.meld(examples.randomHeap2000);
			assert (examples.randomHeap1000.size() == 3000) : "Invalid size, should be 3000, instead is "
					+ examples.randomHeap1000.size();
			assert (examples.randomHeap1000.findMin() == temp) : "Invalid minimum in new heap, should be "
					+ temp + ", instead is" + examples.randomHeap1000.findMin();
			
			assert (examples.randomHeap1000.isValid());
			temp = (examples.randomHeap3000Min > 1) ? 1
					: examples.randomHeap3000Min;
			examples.randomHeap3000.meld(examples.simpleHeap);
			assert (examples.randomHeap3000.size() == 3010) : "Invalid size, should be 3010, instead is "
					+ examples.randomHeap3000.size();
			assert (examples.randomHeap3000.findMin() == temp) : "Invalid minimum in new heap, should be "
					+ temp + ", instead is" + examples.randomHeap3000.findMin();
			
			return true;
		}

	}
}
